package editors.objectedit;
import java.util.ArrayList;
import java.util.Vector;

import main.Config;
import main.ProgramLauncher;

import org.lwjgl.LWJGLException;
import org.lwjgl.input.Keyboard;
import org.lwjgl.input.Mouse;
import org.lwjgl.opengl.GL11;

import physics.Body;
import physics.PhysicalConstants;
import physics.joints.JAngleJoint;
import physics.joints.JDistanceJoint;
import physics.joints.JSpring;
import physics.shapes.Circle;
import physics.shapes.Polygon;
import physics.shapes.Shape;
import physics.tools.Initializer;

import editors.gui.GuiButton;
import editors.gui.GuiCheckbox;
import editors.gui.GuiHandler;
import editors.gui.GuiLabel;
import editors.gui.GuiSettings;
import editors.gui.GuiSlider;
import editors.gui.GuiText;

import tools.Floatmath;
import tools.Help;
import tools.Log;
import tools.Point;
import tools.Profiler;

import game.Game;
import game.controlling.KeyListener;
import game.engine.Empty;
import game.engine.GSync;
import game.engine.TriggerArea;
import game.objects.GOBox;
import game.objects.GODynamic;
import game.objects.GORect;
import graphics.effects.Compositor;
import graphics.main.MainRenderer;
import graphics.objects.GAtmosphereLight;
import graphics.objects.GCircle;
import graphics.objects.GLight;
import graphics.objects.GPointLight;
import graphics.objects.GPolygon;
import graphics.objects.GRect;
import graphics.objects.GShape;
import graphics.objects.GraphicsObject;
import graphics.system.Color;
import graphics.system.GLTools;
import graphics.system.Node;
import graphics.system.Texture;
import graphics.system.TextureContainer;
import graphics.tools.Console;
public class ObjEditRenderer extends MainRenderer {
	private static final float MASSSCALEFACTOR = 0.05f;
	private GuiHandler ghandler;
	private GuiHandler gstatusbar;
	private GuiHandler grender;
	private enum EditorMode {
		PHYSICS, GRAPHICS
	}
	private enum EditorState {
		ADD_POLY, ADD_CIRCLE, ADD_RECT, ADD_LIGHT, ADD_ABMIENT, ADD_SPRING, ADD_DJOINT, ADD_EMPTY, ADD_TRIGGERAREA, ADD_HINGE, SET_NONCOLBODY, RSELECT, MOVE, SCALE, ROTATE, CONNECT, LOAD, NONE
	}
	private EditorMode editormode;
	private EditorState state;
	private GPolygon gpoly;
	private Point bpoint, cmove;
	private GODynamic gobj, gcopy;
	private boolean drawcircle;
	private boolean bodyselected;
	private Body selbody;
	private boolean groselected;
	private boolean colorshadow; // false = color, true = shadow
	private GraphicsObject selgro;
	private boolean selectline;
	private Vector<GraphicsObject> selgros;
	private Vector<Body> selbodies;
	private boolean drawrect;
	private GuiHandler ggraphsettings;
	private GuiHandler gphysettings;
	private GuiHandler ggraph;
	private GuiHandler gphys;
	private Color color;
	private Color glowColor;
	private Color ocolor;
	private Color oglowColor;
	private boolean showNames;
	private boolean anchorset;
	private Texture tex;
	private boolean hasTexConstraint;
	public ObjEditRenderer() {
		super();
		this.simplerender = true;
		this.showConsole = false;
		this.showprofiler = false;
		editormode = EditorMode.PHYSICS;
		state = EditorState.NONE;
		color = new Color(0.5f, 0.5f, 0.5f, 1);
		glowColor = new Color(1, 1, 1, 1);
		ocolor = new Color(0, 0, 1, 1);
		oglowColor = new Color(0, 0, 0, 1);
		initGui();
		bpoint = new Point();
		drawcircle = false;
		bodyselected = false;
		groselected = false;
		drawrect = false;
		hasTexConstraint = false;
		selbody = null;
		showNames = true;
		anchorset = false;
		selgros = new Vector<GraphicsObject>();
		selbodies = new Vector<Body>();
		colorshadow = false;
		selectline = false;
		cmove = new Point();
	}
	public void setGame(Game g) {
		game = g;
		keyListener = new KeyListener();
		g.setKeyListener(keyListener);
		g.engine.graphics.setRenderer(this);
		// g.addGameObject(new GORect(g, new Point(10, 1000), 20, 2000, 0.0f,
		// 0.0f, new Color(0, 0, 0, 1)));
		// g.addGameObject(new GORect(g, new Point(2010, 1000), 20, 2000, 0.0f,
		// 0.0f, new Color(0, 0, 0, 1)));
		/*
		 * GORect floor = new GORect(g, new Point(0, -450), 1000, 150, 0.0f, 0.0f, new Color(0, 0, 0, 1)); g.addGameObject(floor);
		 */
		this.gobj = new GODynamic(g);
		g.addGameObject(gobj);
		gcopy = new GODynamic(g);
		g.addGameObject(gcopy);
		g.engine.stopPhysics();
		gpoly = new GPolygon();
		gpoly.glowColor = Color.black;
		objects.add(gpoly);
		// gobj.loadFile("nt",new BoundingBox(-500,-500,500,500));
		// this.simplerender = false;
	}
	private void initGui() {
		this.ghandler = new GuiHandler();
		this.ggraph = new GuiHandler();
		this.gphys = new GuiHandler();
		this.gstatusbar = new GuiHandler();
		this.ggraphsettings = new GuiHandler();
		this.gphysettings = new GuiHandler();
		grender = new GuiHandler();
		grender.addGuiObject("title", new GuiLabel(new Point(0, 0), 162, "RenderMode"));
		grender.addGuiObject("debug", new GuiButton(new Point(0, -GuiSettings.LINEHEIGHT - 2), 80, "debug"));
		grender.addGuiObject("game", new GuiButton(new Point(82, -GuiSettings.LINEHEIGHT - 2), 80, "game"));
		Point g = new Point(10, height - 10);
		ghandler.addGuiObject("label", new GuiLabel(g, 100, "Editor"));
		ghandler.addGuiObject("labelmode", new GuiLabel(g.add(new Point(110, 0)), 90, "mode"));
		g.y -= GuiSettings.LINEHEIGHT + 2;
		ghandler.addGuiObject("mode_phy", new GuiButton(g, 64, "phys"));
		ghandler.addGuiObject("mode_graph", new GuiButton(g.add(new Point(66, 0)), 64, "graph"));
		g.y -= GuiSettings.LINEHEIGHT + 2;
		ghandler.addGuiObject("move", new GuiButton(g, 64, "move"));
		ghandler.addGuiObject("scale", new GuiButton(g.add(new Point(66, 0)), 64, "scale"));
		ghandler.addGuiObject("rotate", new GuiButton(g.add(new Point(66 * 2, 0)), 68, "rotate"));
		g.y -= GuiSettings.LINEHEIGHT + 5;
		ghandler.addGuiObject("add_poly", new GuiButton(g, 98, "AddPoly"));
		ghandler.addGuiObject("add_circle", new GuiButton(g.add(100, 0), 100, "AddCircle"));
		g.y -= GuiSettings.LINEHEIGHT + 2;
		ghandler.addGuiObject("add_rect", new GuiButton(g, 98, "AddRect"));
		g.y -= GuiSettings.LINEHEIGHT + 5;
		ghandler.addGuiObject("add_spring", new GuiButton(g, 98, "AddSpring"));
		ghandler.addGuiObject("add_djoint", new GuiButton(g.add(100, 0), 100, "AddDJoint"));
		g.y -= GuiSettings.LINEHEIGHT + 2;
		ghandler.addGuiObject("add_hinge", new GuiButton(g, 98, "AddHinge"));
		// ghandler.addGuiObject("add_djoint", new GuiButton(g.add(100,0), 100,"AddDJoint"));
		g.y -= GuiSettings.LINEHEIGHT + 5;
		ghandler.addGuiObject("add_light", new GuiButton(g, 98, "AddLight"));
		ghandler.addGuiObject("add_ambient", new GuiButton(g.add(100, 0), 100, "AddAmbientL"));
		g.y -= GuiSettings.LINEHEIGHT + 2;
		ghandler.addGuiObject("add_triggerarea", new GuiButton(g, 98, "AddTrigger"));
		ghandler.addGuiObject("add_empty", new GuiButton(g.add(100, 0), 100, "AddEmpty"));
		g.y -= GuiSettings.LINEHEIGHT + 5;
		ghandler.addGuiObject("connect", new GuiButton(g, 200, "connect"));
		g.y -= GuiSettings.LINEHEIGHT + 5;
		ghandler.addGuiObject("labelfile", new GuiLabel(g, 200, "File"));
		g.y -= GuiSettings.LINEHEIGHT + 2;
		ghandler.addGuiObject("filename", new GuiText(g, 200));
		g.y -= GuiSettings.LINEHEIGHT + 2;
		ghandler.addGuiObject("save", new GuiButton(g, 95, "save"));
		ghandler.addGuiObject("load", new GuiButton(g.add(new Point(100, 0)), 100, "load"));
		g.y -= GuiSettings.LINEHEIGHT + 2;
		g = new Point(10, height - 10);
		ggraph.addGuiObject("labelgrset", new GuiLabel(g, 200, "GraphicsSettings"));
		g.y -= GuiSettings.LINEHEIGHT + 2;
		ggraph.addGuiObject("zpos", new GuiSlider(g, 200, "z-Position", Byte.MIN_VALUE, Byte.MAX_VALUE, 0, true));
		g.y -= GuiSettings.LINEHEIGHT * 2 + 2;
		ggraph.addGuiObject("red", new GuiSlider(g, 200, "red", 0, 1, color.r));
		g.y -= GuiSettings.LINEHEIGHT * 2 + 2;
		ggraph.addGuiObject("green", new GuiSlider(g, 200, "green", 0, 1, color.g));
		g.y -= GuiSettings.LINEHEIGHT * 2 + 2;
		ggraph.addGuiObject("blue", new GuiSlider(g, 200, "blue", 0, 1, color.b));
		g.y -= GuiSettings.LINEHEIGHT * 2 + 2;
		ggraph.addGuiObject("alpha", new GuiSlider(g, 200, "alpha", 0, 1, color.a));
		g.y -= GuiSettings.LINEHEIGHT * 2 + 2;
		ggraph.addGuiObject("set_color", new GuiLabel(g, 95, "setColor"));
		ggraph.addGuiObject("set_glow", new GuiLabel(g.add(new Point(100, 0)), 100, "glowColor"));
		g.y -= GuiSettings.LINEHEIGHT + 2;
		ggraph.addGuiObject("glow", new GuiCheckbox(g, "Glow"));
		ggraph.addGuiObject("shadow", new GuiCheckbox(g.add(new Point(100, 0)), "Shadow"));
		g.y -= GuiSettings.LINEHEIGHT + 2;
		ggraph.addGuiObject("texture", new GuiCheckbox(g, "Texture"));
		ggraph.addGuiObject("globalcoords", new GuiCheckbox(g.add(new Point(100, 0)), "glob.coords"));
		g.y -= GuiSettings.LINEHEIGHT + 2;
		ggraph.addGuiObject("texname", new GuiText(g, 200));
		g.y -= GuiSettings.LINEHEIGHT + 5;
		// ghandler.addGuiObject("labelphys", new GuiLabel(g,200,"Physics"));
		// g.y -= 22;
		gphys.addGuiObject("labelphyset", new GuiLabel(g, 200, "PhysicsSettings"));
		g.y -= GuiSettings.LINEHEIGHT + 2;
		gphys.addGuiObject("mass", new GuiSlider(g, 200, "mass", 0.1f, 100, 3));
		g.y -= GuiSettings.LINEHEIGHT * 2 + 2;
		gphys.addGuiObject("friction", new GuiSlider(g, 200, "friction", 0, 3, PhysicalConstants.FRICTION));
		g.y -= GuiSettings.LINEHEIGHT * 2 + 2;
		gphys.addGuiObject("restitution", new GuiSlider(g, 200, "restitution", 0, 2));
		g.y -= GuiSettings.LINEHEIGHT * 2 + 2;
		gphys.addGuiObject("static", new GuiCheckbox(g, "static"));
		gphys.addGuiObject("auto_add", new GuiCheckbox(g.add(100, 0), "auto add"));
		g.y -= GuiSettings.LINEHEIGHT * 2 + 2;
		ggraph.setLabelBackground("set_color", color);
		ggraph.setLabelBackground("set_glow", glowColor);
		gstatusbar.addGuiObject("status", new GuiLabel(new Point(0, 20), width, "Status"));
		((GuiLabel) gstatusbar.getObject("status")).centertext = true;
		ggraph.setChecked("shadow", true);
		g = new Point(0, 0);
		ggraphsettings.addGuiObject("title", new GuiLabel(g, 150, "Object Settings"));
		g.y -= GuiSettings.LINEHEIGHT + 2;
		ggraphsettings.addGuiObject("zpos", new GuiSlider(g, 150, "z-Position", Byte.MIN_VALUE, Byte.MAX_VALUE, 0, true));
		g.y -= GuiSettings.LINEHEIGHT * 2 + 2;
		ggraphsettings.addGuiObject("red", new GuiSlider(g, 150, "red", 0, 1, 0f));
		g.y -= GuiSettings.LINEHEIGHT * 2 + 2;
		ggraphsettings.addGuiObject("green", new GuiSlider(g, 150, "green", 0, 1, 0));
		g.y -= GuiSettings.LINEHEIGHT * 2 + 2;
		ggraphsettings.addGuiObject("blue", new GuiSlider(g, 150, "blue", 0, 1, 0));
		g.y -= GuiSettings.LINEHEIGHT * 2 + 2;
		ggraphsettings.addGuiObject("alpha", new GuiSlider(g, 150, "alpha", 0, 1, 1));
		g.y -= GuiSettings.LINEHEIGHT * 2 + 2;
		ggraphsettings.addGuiObject("set_color", new GuiLabel(g, 150, "color"));
		g.y -= GuiSettings.LINEHEIGHT + 2;
		ggraphsettings.addGuiObject("set_glow", new GuiLabel(g, 150, "glowColor"));
		g.y -= GuiSettings.LINEHEIGHT * 2 + 2;
		ggraphsettings.addGuiObject("glow", new GuiCheckbox(g, "Glow"));
		g.y -= GuiSettings.LINEHEIGHT + 2;
		ggraphsettings.addGuiObject("shadow", new GuiCheckbox(g, "Shadow"));
		g.y -= GuiSettings.LINEHEIGHT + 2;
		ggraphsettings.addGuiObject("texture", new GuiCheckbox(g, "Texture"));
		g.y -= GuiSettings.LINEHEIGHT + 2;
		ggraphsettings.addGuiObject("texlabel", new GuiLabel(g, 150, "TextureName"));
		g.y -= GuiSettings.LINEHEIGHT + 2;
		ggraphsettings.addGuiObject("texname", new GuiText(g, 150));
		g.y -= GuiSettings.LINEHEIGHT + 2;
		ggraphsettings.addGuiObject("normal", new GuiCheckbox(g, "Specular"));
		g.y -= GuiSettings.LINEHEIGHT + 2;
		ggraphsettings.addGuiObject("nlabel", new GuiLabel(g, 150, "Normalmap"));
		g.y -= GuiSettings.LINEHEIGHT + 2;
		ggraphsettings.addGuiObject("normalname", new GuiText(g, 150));
		g.y -= GuiSettings.LINEHEIGHT + 2;
		ggraphsettings.addGuiObject("globalcoord", new GuiCheckbox(g, "global Coords"));
		g.y -= GuiSettings.LINEHEIGHT + 2;
		ggraphsettings.addGuiObject("objectnamelabel", new GuiLabel(g, 150, "ObjectName"));
		g.y -= GuiSettings.LINEHEIGHT + 2;
		ggraphsettings.addGuiObject("objectname", new GuiText(g, 150));
		g = new Point(0, 0);
		gphysettings.addGuiObject("title", new GuiLabel(g, 150, "Object Settings"));
		g.y -= GuiSettings.LINEHEIGHT + 2;
		gphysettings.addGuiObject("mass", new GuiSlider(g, 150, "mass", 0.1f, 100, 3));
		g.y -= GuiSettings.LINEHEIGHT * 2 + 2;
		gphysettings.addGuiObject("friction", new GuiSlider(g, 150, "friction", 0, 3, PhysicalConstants.FRICTION));
		g.y -= GuiSettings.LINEHEIGHT * 2 + 2;
		gphysettings.addGuiObject("restitution", new GuiSlider(g, 150, "restitution", 0, 2));
		g.y -= GuiSettings.LINEHEIGHT * 2 + 2;
		gphysettings.addGuiObject("static", new GuiCheckbox(g, "static"));
		g.y -= GuiSettings.LINEHEIGHT + 2;
		gphysettings.addGuiObject("add_to_graphic", new GuiButton(g, 150, "add to graphic"));
		g.y -= GuiSettings.LINEHEIGHT + 2;
		gphysettings.addGuiObject("objectnamelabel", new GuiLabel(g, 150, "ObjectName"));
		g.y -= GuiSettings.LINEHEIGHT + 2;
		gphysettings.addGuiObject("objectname", new GuiText(g, 150));
		g.y -= GuiSettings.LINEHEIGHT + 2;
		gphysettings.addGuiObject("set_colbody", new GuiButton(g, 150, "set non-colbody"));
	}
	@Override
	public void handle() {
		control();
		handleGui();
		editorControl();
		handleGraphicLogic();
		game.engine.handle();
		frame++;
	}
	// ######################################################################################## CONTROL #############################################################
	private void editorControl() {
		// mouse on gui? yes: don't add/move/rotate ... objects!
		if (mouseIn())
			return;
		switch (state) {
			case ADD_POLY : {
				if (keyListener.isButtonTouched(0)) {
					this.gpoly.addPoint(new Point(keyListener.mp.x, keyListener.mp.y));
				}
				break;
			}
			case ADD_CIRCLE : {
				if (keyListener.isButtonTouched(0)) {
					bpoint = new Point(keyListener.mp);
					this.drawcircle = true;
				}
				if (keyListener.isButtonReleased(0) && drawcircle && editormode == EditorMode.PHYSICS) {
					float friction = gphys.getSliderValue("friction");
					float restitution = gphys.getSliderValue("restitution");
					Circle c = new Circle(bpoint, Floatmath.max(bpoint.distance(keyListener.mp), 0.5f));
					float mass = Initializer.calcMass(c, gphys.getSliderValue("mass")) * MASSSCALEFACTOR;
					Body b = new Body(c, Floatmath.min(mass, 100));
					b.friction = friction;
					b.restitution = restitution;
					if (gphys.isChecked("static"))
						b.setStatic();
					gobj.addBody(b);
					if (gphys.isChecked("auto_add")) {
						gobj.addGraphicsObject(gGetCircle(), new GSync(b));
					}
					drawcircle = false;
				}
				else if (keyListener.isButtonReleased(0) && drawcircle) {
					GraphicsObject g = gGetCircle();
					gobj.addGraphicsObject(g, new GSync());
					drawcircle = false;
				}
				break;
			}
			case ADD_LIGHT : {
				if (keyListener.isButtonTouched(0) && editormode == EditorMode.GRAPHICS) {
					bpoint = new Point(keyListener.mp);
					this.drawcircle = true;
				}
				if (keyListener.isButtonReleased(0) && drawcircle && editormode == EditorMode.GRAPHICS) {
					if (keyListener.mp.distance(bpoint) > 0.5f) {
						GPointLight pl = new GPointLight(bpoint, keyListener.mp.distance(bpoint), color);
						gobj.addGraphicsObject(pl, new GSync());
						drawcircle = false;
					}
					else {
						statM("light radius too small!");
					}
				}
				break;
			}
			case ADD_ABMIENT : {
				if (keyListener.isButtonTouched(0) && editormode == EditorMode.GRAPHICS) {
					bpoint = new Point(keyListener.mp);
					this.drawcircle = true;
				}
				if (keyListener.isButtonReleased(0) && drawcircle && editormode == EditorMode.GRAPHICS) {
					if (keyListener.mp.distance(bpoint) > 0.5f) {
						GAtmosphereLight al = new GAtmosphereLight(bpoint, keyListener.mp.distance(bpoint), color);
						gobj.addGraphicsObject(al, new GSync());
						drawcircle = false;
					}
					else {
						statM("light radius too small!");
					}
				}
				break;
			}
			case ADD_RECT : {
				if (keyListener.isButtonTouched(0)) {
					bpoint = new Point(keyListener.mp);
					this.drawrect = true;
					if (editormode == EditorMode.GRAPHICS && keyListener.isKeyPressed(Keyboard.KEY_LCONTROL)) {
						tex = TextureContainer.getTexture(ggraph.getText("texname"));
						if (tex != null) {
							Help.p("bla");
							this.hasTexConstraint = true;
						}
						else {
							this.hasTexConstraint = false;
						}
					}
				}
				if (keyListener.isButtonReleased(0) && drawrect && editormode == EditorMode.PHYSICS) {
					float friction = gphys.getSliderValue("friction");
					float restitution = gphys.getSliderValue("restitution");
					float xmin = Math.min(bpoint.x, keyListener.mp.x);
					float xmax = Math.max(bpoint.x, keyListener.mp.x);
					float ymin = Math.min(bpoint.y, keyListener.mp.y);
					float ymax = Math.max(bpoint.y, keyListener.mp.y);
					Point c = new Point(xmin + xmax, ymin + ymax).mul(0.5f);
					Point d = new Point(xmax, ymax).sub(new Point(xmin, ymin)).mul(0.5f);
					if (d.length() < 0.5f) {
						statM("rect is too small!");
						drawrect = false;
						break;
					}
					Point v[] = {new Point(-d.x, -d.y), new Point(d.x, -d.y), new Point(d.x, d.y), new Point(-d.x, d.y)};
					Polygon poly = new Polygon(c, v);
					float mass = Initializer.calcMass(poly, gphys.getSliderValue("mass")) * MASSSCALEFACTOR;
					Body b = new Body(poly, Floatmath.min(mass, 100));
					b.friction = friction;
					b.restitution = restitution;
					if (gphys.isChecked("static"))
						b.setStatic();
					gobj.addBody(b);
					drawrect = false;
					if (gphys.isChecked("auto_add")) {
						gobj.addGraphicsObject(gGetRect(), new GSync(b));
					}
				}
				else if (keyListener.isButtonReleased(0) && drawrect) {
					GraphicsObject g = gGetRect();
					if (g != null)
						gobj.addGraphicsObject(g, new GSync());
					drawrect = false;
				}
				break;
			}
			case CONNECT : {
				if (!bodyselected) {
					if (keyListener.isButtonTouched(0)) {
						Body b = gobj.getBodyAt(keyListener.mp);
						if (b != null) {
							bodyselected = true;
							selbody = b;
						}
					}
				}
				else {
					if (keyListener.isButtonTouched(0)) {
						GraphicsObject g = gobj.getGROAt(keyListener.mp);
						if (g != null) { // CONNECT THEM
							gobj.remGraphicsObject(g);
							gobj.addGraphicsObject(g, new GSync(selbody, g.node.pos.sub(selbody.pos), g.node.apos));
							bodyselected = false;
							groselected = false;
						}
					}
				}
				break;
			}
			case LOAD : {
				if (keyListener.isButtonTouched(0)) {
					bpoint = keyListener.mp;
					drawrect = true;
				}
				else if (keyListener.isButtonReleased(0) && drawrect) {
					if (keyListener.mp.distance(bpoint) > 0.1f) {
						float xmin = Math.min(bpoint.x, keyListener.mp.x);
						float xmax = Math.max(bpoint.x, keyListener.mp.x);
						float ymin = Math.min(bpoint.y, keyListener.mp.y);
						float ymax = Math.max(bpoint.y, keyListener.mp.y);
						float s = Floatmath.max(xmax - xmin, ymax - ymin);
						gobj.loadFile(ghandler.getText("filename"), new BoundingBox(xmin, ymin, xmin + s, ymin + s));
						drawrect = false;
					}
					else {
						gobj.loadFile(ghandler.getText("filename"), keyListener.mp);
						drawrect = false;
					}
				}
				break;
			}
			case MOVE : {
				if (keyListener.isButtonTouched(0) && bodyselected) {
					bpoint = keyListener.mp;
				}
				else if (bodyselected && (keyListener.isButtonPressed(0) || keyListener.isButtonReleased(0))) {
					Point dx = keyListener.mp.sub(bpoint);
					for (Body b : selbodies) {
						b.pos.sAdd(dx);
						b.stop();
						b.wakeUp();
						b.update(0);
					}
					bpoint = keyListener.mp;
				}
				if (keyListener.isButtonTouched(0) && groselected) {
					bpoint = keyListener.mp;
				}
				else if (groselected && (keyListener.isButtonPressed(0) || keyListener.isButtonReleased(0))) {
					Point dx = keyListener.mp.sub(bpoint);
					for (GraphicsObject g : selgros) {
						g.node.pos.sAdd(dx);
						gobj.getSync(g).offset.sAdd(dx);
					}
					bpoint = keyListener.mp;
				}
				break;
			}
			case ROTATE : {
				if (keyListener.isButtonTouched(0) && bodyselected) {
					bpoint = keyListener.mp;
				}
				else if (bodyselected && (keyListener.isButtonPressed(0) || keyListener.isButtonReleased(0))) {
					Point c = new Point();
					for (Body b : selbodies)
						c.sAdd(b.pos);
					c.sMul(1.0f / selbodies.size());
					float a = bpoint.sub(c).angle() - keyListener.mp.sub(c).angle();
					for (Body b : selbodies) {
						Point offs = b.pos.sub(c);
						offs = offs.rotate(-a);
						b.pos = c.add(offs);
						b.apos += -a;
						b.stop();
						b.wakeUp();
						b.update(0);
					}
					bpoint = keyListener.mp;
				}
				if (keyListener.isButtonTouched(0) && groselected) {
					bpoint = keyListener.mp;
				}
				else if (groselected && (keyListener.isButtonPressed(0) || keyListener.isButtonReleased(0))) {
					Point c = new Point();
					for (GraphicsObject g : selgros)
						c.sAdd(g.node.pos);
					c.sMul(1.0f / selgros.size());
					float a = bpoint.sub(c).angle() - keyListener.mp.sub(c).angle();
					for (GraphicsObject g : selgros) {
						Point offs = g.node.pos.sub(c);
						offs = offs.rotate(-a);
						g.node.pos = c.add(offs);
						g.node.apos += -a;
					}
					bpoint = keyListener.mp;
				}
				break;
			}
			case SCALE : {
				if (keyListener.isButtonTouched(0) && groselected) {
					Point c = new Point();
					for (GraphicsObject g : selgros)
						c.sAdd(g.node.pos);
					c.sMul(1.0f / (float) selgros.size());
					bpoint = new Point();
					bpoint.x = keyListener.mp.distance(c);
					bpoint.y = 1;
				}
				else if (groselected && (keyListener.isButtonPressed(0) || keyListener.isButtonReleased(0))) {
					Point c = new Point();
					for (GraphicsObject g : selgros) {
						c.sAdd(g.node.pos);
					}
					c.sMul(1.0f / (float) selgros.size());
					float scale = ((c.distance(keyListener.mp) - bpoint.x) * 0.01f);
					bpoint.y += scale;
					// Help.p(scale);
					for (GraphicsObject g : selgros) {
						Point offs = g.node.pos.sub(c).mul(bpoint.y);
						g.node.pos = c.add(offs);
						g.node.scale.x *= bpoint.y;
						g.node.scale.y *= bpoint.y;
						g.node.boundingrad *= bpoint.y;
						g.node.scale.x = Floatmath.max(0.01f, g.node.scale.x);
						g.node.scale.y = Floatmath.max(0.01f, g.node.scale.y);
					}
					bpoint.y = 1;
					bpoint.x = keyListener.mp.distance(c);
				}
				break;
			}
			case ADD_SPRING : {
				if (keyListener.isButtonTouched(0)) {
					if (!anchorset) {
						Body b = gobj.getBodyAt(keyListener.mp);
						if (b != null) {
							selbody = b;
							bpoint = keyListener.mp;
							anchorset = true;
							statM("click on second body");
						}
					}
					else {
						Body b = gobj.getBodyAt(keyListener.mp, selbody);
						if (b != null) {
							JSpring s = new JSpring(selbody, b, bpoint, keyListener.mp, bpoint.distance(keyListener.mp), 50, 0.01f);
							gobj.addJoint(s);
							anchorset = false;
						}
						else {
							anchorset = false;
						}
					}
				}
				break;
			}
			case ADD_DJOINT : {
				if (keyListener.isButtonTouched(0)) {
					if (!anchorset) {
						Body b = gobj.getBodyAt(keyListener.mp);
						if (b != null) {
							selbody = b;
							bpoint = keyListener.mp;
							anchorset = true;
							statM("click on second body");
						}
					}
					else {
						Body b = gobj.getBodyAt(keyListener.mp, selbody);
						if (b != null) {
							JDistanceJoint s = new JDistanceJoint(selbody, b, bpoint, keyListener.mp, bpoint.distance(keyListener.mp));
							gobj.addJoint(s);
							anchorset = false;
						}
						else {
							anchorset = false;
						}
					}
				}
				break;
			}
			case ADD_HINGE : {
				if (keyListener.isButtonTouched(0) && !anchorset) {
					Body b = gobj.getBodyAt(keyListener.mp);
					if (b != null) {
						selbody = b;
						anchorset = true;
						if (keyListener.isKeyPressed(Keyboard.KEY_LCONTROL)) {
							bpoint = b.pos;
						}
						else {
							bpoint = keyListener.mp;
						}
						statM("click on second body");
					}
				}
				else if (keyListener.isButtonTouched(0) && anchorset) {
					Body b = gobj.getBodyAt(keyListener.mp, selbody);
					if (b != null && b.id != selbody.id) {
						// gobj.addJoint(new JAngleJoint(selbody,b,1));
						gobj.addJoint(new JDistanceJoint(selbody, b, bpoint, bpoint, 0));
						selbody.setNonColliding(b);
						anchorset = false;
					}
				}
				break;
			}
			case ADD_EMPTY : {
				if (keyListener.isButtonTouched(0)) {
					gobj.addGraphicsObject(new Empty(keyListener.mp), new GSync());
				}
				break;
			}
			case ADD_TRIGGERAREA : {
				if (keyListener.isButtonTouched(0) && !drawrect) {
					bpoint = keyListener.mp;
					drawrect = true;
				}
				else {
					if (keyListener.isButtonTouched(0) && drawrect) {
						if (keyListener.mp.distance(bpoint) > 1) {
							TriggerArea t = new TriggerArea(bpoint, keyListener.mp);
							gobj.addGraphicsObject(t, new GSync());
							drawrect = false;
						}
						else {
							statM("rect to smal!");
						}
					}
				}
				break;
			}
			case RSELECT : {
				if (keyListener.isButtonTouched(0)) {
					bpoint = keyListener.mp;
					drawrect = true;
				}
				if (keyListener.isButtonReleased(0)) {
					drawrect = false;
					this.selbodies.addAll(gobj.getBodiesInRect(bpoint, keyListener.mp));
					if (selbodies.size() > 0)
						bodyselected = true;
					this.selgros.addAll(gobj.getGROsInRect(bpoint, keyListener.mp));
					if (selgros.size() > 0)
						groselected = true;
					if (!keyListener.isKeyPressed(Keyboard.KEY_LSHIFT)) {
						state = EditorState.NONE;
					}
				}
				break;
			}
			case SET_NONCOLBODY : {
				if (keyListener.isButtonTouched(0)) {
					Body b = gobj.getBodyAt(keyListener.mp);
					if (b != null && b.id != selbody.id) {
						b.setNonColliding(selbody);
						statM("colbody set!");
					}
				}
				break;
			}
		}
		if (editormode == EditorMode.PHYSICS) {
			if (keyListener.isButtonPressed(1)) {
				Body b = gobj.getBodyAt(keyListener.mp);
				if (b != null) {
					selectline = true;
					bpoint = b.pos;
				}
				else {
					selectline = false;
				}
			}
			if (keyListener.isButtonReleased(1)) { // select body
				Body b = gobj.getBodyAt(keyListener.mp);
				if (b != null) {
					selectline = false;
					if (bodyselected && keyListener.isKeyPressed(Keyboard.KEY_LSHIFT)) {
						if (!selbodies.contains(b))
							selbodies.add(b);
					}
					else {
						bodyselected = true;
						selbody = b;
						selbodies.clear();
						selbodies.add(b);
						drawcircle = false;
						drawrect = false;
						gpoly.clearPoints();
						if (state == EditorState.ADD_CIRCLE || state == EditorState.ADD_POLY)
							state = EditorState.NONE;
						loadBodyEditor();
					}
				}
				else {
					bodyselected = false;
					selectline = false;
					selbodies.clear();
				}
			}
		}
		else {
			if (keyListener.isButtonPressed(1)) {
				GraphicsObject g = gobj.getGROAt(keyListener.mp);
				if (g != null) {
					selectline = true;
					bpoint = g.node.pos;
				}
				else {
					selectline = false;
				}
			}
			if (keyListener.isButtonReleased(1)) {// select gro
				GraphicsObject g = gobj.getGROAt(keyListener.mp);
				if (g != null) {
					selectline = false;
					if (groselected && keyListener.isKeyPressed(Keyboard.KEY_LSHIFT)) {
						if (!selgros.contains(g))
							selgros.add(g);
					}
					else {
						groselected = true;
						selgro = g;
						selgros.clear();
						selgros.add(g);
						drawcircle = false;
						drawrect = false;
						gpoly.clearPoints();
						if (state == EditorState.ADD_CIRCLE || state == EditorState.ADD_POLY)
							state = EditorState.NONE;
						ocolor = g.color;
						oglowColor = g.glowColor;
						String n = gobj.getName(selgro);
						ggraphsettings.editSetText("objectname", n == null ? "" : n);
						ggraphsettings.setSliderValue("zpos", selgro.node.zpos);
						this.setoSliderColor(ocolor);
						this.colorshadow = false; // color selection mode
						if (g.isshape) {
							ggraphsettings.setChecked("glow", ((GShape) g).hasGlow());
							ggraphsettings.setChecked("shadow", ((GShape) g).hasShadow());
							if (g instanceof GShape) {
								GShape r = (GShape) g;
								if (r.hasTexture()) {
									ggraphsettings.setChecked("texture", r.hasTexture());
									ggraphsettings.editSetText("texname", r.getTextureName());
								}
								else {
									ggraphsettings.setChecked("texture", false);
									ggraphsettings.editSetText("texname", "");
								}
								if (r.hasNormalMap()) {
									ggraphsettings.setChecked("normal", true);
									ggraphsettings.editSetText("normalname", r.getNormalName());
								}
								else {
									ggraphsettings.setChecked("normal", false);
									ggraphsettings.editSetText("normalname", "");
								}
								ggraphsettings.setChecked("globalcoord", r.hasGlobalCoords());
							}
						}
					}
				}
				else {
					groselected = false;
					selectline = false;
					selgros.clear();
				}
			}
		}
	}
	// ############################################################################################################################################
	private boolean mouseIn() {
		Point mp = this.getMousePosOnScreen();
		return ghandler.mouseIn(mp) || ggraph.mouseIn(mp) || gphys.mouseIn(mp) || this.gphysettings.mouseIn(mp) || this.ggraphsettings.mouseIn(mp) || this.grender.mouseIn(mp);
	}
	private void loadBodyEditor() {
		gphysettings.setSliderValue("mass", selbodies.get(0).mass);
		gphysettings.setSliderValue("friction", selbodies.get(0).friction);
		gphysettings.setSliderValue("restitution", selbodies.get(0).restitution);
		gphysettings.setChecked("static", selbodies.get(0).isStatic());
		String n = gobj.getName(selbody);
		gphysettings.editSetText("objectname", n == null ? "" : n);
	}
	private GraphicsObject gGetCircle() {
		GCircle c = new GCircle(bpoint, Floatmath.max(bpoint.distance(keyListener.mp), 0.5f), 0, getColor());
		c.setGlow(ggraph.isChecked("glow"));
		if (ggraph.isChecked("glow")) {
			c.glowColor = getColor();
		}
		else {
			c.glowColor = new Color(0, 0, 0, 1);
		}
		c.node.zpos = (byte) Math.max(Byte.MIN_VALUE, Math.min(ggraph.getSliderValue("zpos"), Byte.MAX_VALUE));
		c.setShadow(ggraph.isChecked("shadow"));
		return c;
	}
	private GraphicsObject gGetRect() {
		Point c, d;
		if (!this.hasTexConstraint) {
			float xmin = Math.min(bpoint.x, keyListener.mp.x);
			float xmax = Math.max(bpoint.x, keyListener.mp.x);
			float ymin = Math.min(bpoint.y, keyListener.mp.y);
			float ymax = Math.max(bpoint.y, keyListener.mp.y);
			c = new Point(xmin + xmax, ymin + ymax).mul(0.5f);
			d = new Point(xmax, ymax).sub(new Point(xmin, ymin));
		}
		else {
			c = new Point(bpoint);
			d = c.sub(keyListener.mp);
			float l = d.length();
			float asp = (float) tex.width / (float) tex.height;
			d.x = l;
			d.y = l / asp;
			this.hasTexConstraint = false;
		}
		if (d.length() < 0.5f) {
			statM("rect is too small!");
			drawrect = false;
			return null;
		}
		GRect r = new GRect(c, d.x, d.y, 0, getColor());
		r.setGlow(ggraph.isChecked("glow"));
		if (ggraph.isChecked("glow")) {
			r.glowColor = getColor();
		}
		else {
			r.glowColor = new Color(0, 0, 0, 1);
		}
		r.setShadow(ggraph.isChecked("shadow"));
		r.node.zpos = (byte) Math.max(Byte.MIN_VALUE, Math.min(ggraph.getSliderValue("zpos"), Byte.MAX_VALUE));
		if (ggraph.isChecked("texture")) {
			Texture t = TextureContainer.getTexture(ggraph.getText("texname"));
			if (t != null) {
				r.setTexture(t);
				Texture n = TextureContainer.getTexture(ggraph.getText("texname") + "_n");
				if (n != null) {
					r.setNormalTexture(n);
				}
			}
			else {
				statM("no such texture!: " + ggraph.getText("texname"));
			}
		}
		if (ggraph.isChecked("globalcoords")) {
			r.setGlobalCoords(true);
		}
		else {
			r.setGlobalCoords(false);
		}
		return r;
	}
	private Color getColor() {
		Color c = new Color();
		c.r = ggraph.getSliderValue("red");
		c.g = ggraph.getSliderValue("green");
		c.b = ggraph.getSliderValue("blue");
		c.a = ggraph.getSliderValue("alpha");
		return c;
	}
	private Color getColorObj() {
		Color c = new Color();
		c.r = ggraphsettings.getSliderValue("red");
		c.g = ggraphsettings.getSliderValue("green");
		c.b = ggraphsettings.getSliderValue("blue");
		c.a = ggraphsettings.getSliderValue("alpha");
		return c;
	}
	private void setoSliderColor(Color c) {
		ggraphsettings.setSliderValue("red", c.r);
		ggraphsettings.setSliderValue("green", c.g);
		ggraphsettings.setSliderValue("blue", c.b);
		ggraphsettings.setSliderValue("alpha", c.a);
	}
	private void setSliderColor(Color c) {
		ggraph.setSliderValue("red", c.r);
		ggraph.setSliderValue("green", c.g);
		ggraph.setSliderValue("blue", c.b);
		ggraph.setSliderValue("alpha", c.a);
	}
	// ######################################################################################## GUI #############################################################
	private void handleGui() {
		if (ghandler.isClicked("mode_phy")) {
			this.editormode = EditorMode.PHYSICS;
			groselected = false;
		}
		if (ghandler.isClicked("mode_graph")) {
			this.editormode = EditorMode.GRAPHICS;
			bodyselected = false;
		}
		String m = "";
		switch (editormode) {
			case PHYSICS :
				m = "physics";
				break;
			case GRAPHICS :
				m = "graphics";
				break;
		}
		ghandler.labelSetText("labelmode", m);
		if (ghandler.isClicked("add_poly")) {
			this.state = EditorState.ADD_POLY;
			this.gpoly.clearPoints();
			drawcircle = false;
			drawrect = false;
			statM("add points to polygon - press enter to finish");
		}
		else if (ghandler.isClicked("add_circle")) {
			this.state = EditorState.ADD_CIRCLE;
			this.gpoly.clearPoints();
			drawcircle = false;
			this.drawrect = false;
			statM("click and drag to add circle");
		}
		else if (ghandler.isClicked("add_rect")) {
			this.state = EditorState.ADD_RECT;
			this.gpoly.clearPoints();
			drawcircle = false;
			this.drawrect = false;
			statM("click and drag to add rect");
		}
		else if (ghandler.isClicked("add_ambient")) {
			this.state = EditorState.ADD_ABMIENT;
			this.gpoly.clearPoints();
			drawcircle = false;
			this.drawrect = false;
			statM("click and drag to add ambient light");
		}
		else if (ghandler.isClicked("add_light")) {
			this.editormode = EditorMode.GRAPHICS;
			this.state = EditorState.ADD_LIGHT;
			this.gpoly.clearPoints();
			drawcircle = false;
			this.drawrect = false;
			statM("click and drag to add light");
		}
		else if (ghandler.isClicked("add_spring")) {
			drawcircle = false;
			drawrect = false;
			gpoly.clearPoints();
			this.editormode = EditorMode.PHYSICS;
			this.state = EditorState.ADD_SPRING;
			statM("click on first body");
		}
		else if (ghandler.isClicked("add_djoint")) {
			drawcircle = false;
			drawrect = false;
			gpoly.clearPoints();
			this.editormode = EditorMode.PHYSICS;
			this.state = EditorState.ADD_DJOINT;
			statM("click on first body");
		}
		else if (ghandler.isClicked("add_empty")) {
			drawcircle = false;
			drawrect = false;
			gpoly.clearPoints();
			this.state = EditorState.ADD_EMPTY;
			statM("click to add empty");
		}
		else if (ghandler.isClicked("add_triggerarea")) {
			drawcircle = false;
			drawrect = false;
			gpoly.clearPoints();
			this.state = EditorState.ADD_TRIGGERAREA;
			statM("click to add triggerarea");
		}
		else if (ghandler.isClicked("add_hinge")) {
			drawcircle = false;
			drawrect = false;
			gpoly.clearPoints();
			this.state = EditorState.ADD_HINGE;
			anchorset = false;
			statM("click on first body");
		}
		else if (ghandler.isClicked("move")) {
			state = EditorState.MOVE;
		}
		else if (ghandler.isClicked("rotate")) {
			state = EditorState.ROTATE;
		}
		else if (ghandler.isClicked("scale")) {
			state = EditorState.SCALE;
		}
		if (bodyselected) {
			if (gphysettings.isClicked()) {
				float mass = gphysettings.getSliderValue("mass");
				float friction = gphysettings.getSliderValue("friction");
				float restitution = gphysettings.getSliderValue("restitution");
				for (Body b : selbodies) {
					b.mass = Initializer.calcMass(b.shape, mass);
					b.friction = friction;
					b.restitution = restitution;
					if (gphysettings.isChecked("static")) {
						b.setStatic();
					}
					else {
						b.unsetStatic(mass);
						b.wakeUp();
					}
				}
				if (gphysettings.isClicked("add_to_graphic")) {
					if (bodyselected) {
						for(Body b:selbodies){
							Shape s = b.shape;
							if (s instanceof Polygon) {
								Point v[] = ((Polygon) s).pointsOffset;
								Color c = getColor();
								gobj.addGraphicsObject(new GPolygon(b.pos, v, 0, c),
										new GSync(b));
							} else if (s instanceof Circle) {
								gobj.addGraphicsObject(new GCircle(b.pos,
										((Circle) s).radius, 0, getColor()), new GSync(
										b));
							}
						}
						selbody = null;
						bodyselected = false;
						selbodies.clear();
					}
				}
				if (gphysettings.isClicked("set_colbody")) {
					this.state = EditorState.SET_NONCOLBODY;
					drawcircle = false;
					drawrect = false;
					gpoly.clearPoints();
					anchorset = false;
					statM("click on second body!");
				}
			}
			if (gphysettings.inTextEditMode()) {
				gobj.setName(selbody, (gphysettings.getText("objectname")));
			}
		}
		if (ggraph.isClicked("set_color")) {
			this.setSliderColor(color);
			this.colorshadow = false;
		}
		if (ggraph.isClicked("set_glow")) {
			this.setSliderColor(glowColor);
			this.colorshadow = true;
		}
		if (groselected) {
			if (ggraphsettings.isClicked("set_color")) {
				this.setoSliderColor(ocolor);
				this.colorshadow = false;
			}
			if (ggraphsettings.isClicked("set_glow")) {
				this.setoSliderColor(oglowColor);
				this.colorshadow = true;
			}
			if (ggraphsettings.isClicked()) {
				if (!colorshadow) {
					ocolor = getColorObj();
				}
				else {
					oglowColor = getColorObj();
				}
				ggraphsettings.setLabelBackground("set_color", ocolor);
				ggraphsettings.setLabelBackground("set_glow", oglowColor);
				for (GraphicsObject g : selgros) {
					g.node.zpos = (byte) Math.max(Byte.MIN_VALUE, Math.min(ggraphsettings.getSliderValue("zpos"), Byte.MAX_VALUE));
					g.glowColor = oglowColor;
					g.color = ocolor;
					if (g instanceof GShape) {
						GShape s = (GShape) g;
						s.setGlow(ggraphsettings.isChecked("glow"));
						s.setShadow(ggraphsettings.isChecked("shadow"));
						if (ggraphsettings.isChecked("texture")) {
							Texture t = TextureContainer.getTexture(ggraphsettings.getText("texname"));
							if (t != null) {
								s.setHasTexture(true);
								s.setTexture(t);
							}
						}
						else {
							s.setHasTexture(false);
							s.setTexture(null);
						}
						if (s.hasTexture()) {
							s.setGlobalCoords(ggraphsettings.isChecked("globalcoord"));
						}
						if (ggraphsettings.isChecked("normal")) {
							Texture t = TextureContainer.getTexture(ggraphsettings.getText("normalname"));
							if (t != null)
								s.setNormalTexture(t);
							else
								statM("not such texture for normalmap!:" + ggraphsettings.getText("normalname"));
						}
						else {
							s.setNormalTexture(null);
						}
					}
				}
				if (ggraphsettings.isClicked("zpos")) {
					this.zOrder();
				}
			}
			if (ggraphsettings.inTextEditMode()) {
				if (!ggraphsettings.getText("objectname").equals("")) {
					gobj.setName(selgro, (ggraphsettings.getText("objectname")));
				}
			}
		}
		else {
			if (!colorshadow) {
				color = getColor();
			}
			else {
				glowColor = getColor();
			}
			ggraph.setLabelBackground("set_color", color);
			ggraph.setLabelBackground("set_glow", glowColor);
		}
		if (ghandler.isClicked("connect")) {
			cancleAll();
			statM("1: click physics object 2: click graphics object ");
			this.state = EditorState.CONNECT;
		}
		if (ghandler.isClicked("save")) {
			if (!ghandler.getText("filename").equals("")) {
				gobj.saveFile(ghandler.getText("filename"));
			}
		}
		if (ghandler.isClicked("load")) {
			if (this.state == EditorState.LOAD && keyListener.isButtonTouched(0)) {
				if (!ghandler.getText("filename").equals("")) {
					gobj.loadFile(ghandler.getText("filename"), Point.ZERO);
					cancleAll();
				}
			}
			else {
				this.drawcircle = false;
				this.drawrect = false;
				anchorset = false;
				this.gpoly.clearPoints();
				state = EditorState.LOAD;
			}
		}
		switch (editormode) {
			case PHYSICS :
				ghandler.setButtonSelected("mode_phy");
				break;
			case GRAPHICS :
				ghandler.setButtonSelected("mode_graph");
				break;
		}
		switch (state) {
			case MOVE :
				ghandler.setButtonSelected("move");
				break;
			case ROTATE :
				ghandler.setButtonSelected("rotate");
				break;
			case SCALE :
				ghandler.setButtonSelected("scale");
				break;
			case ADD_POLY :
				ghandler.setButtonSelected("add_poly");
				break;
			case ADD_CIRCLE :
				ghandler.setButtonSelected("add_circle");
				break;
			case ADD_RECT :
				ghandler.setButtonSelected("add_rect");
				break;
			case CONNECT :
				ghandler.setButtonSelected("connect");
				break;
			case ADD_LIGHT :
				ghandler.setButtonSelected("add_light");
				break;
			case ADD_SPRING :
				ghandler.setButtonSelected("add_spring");
				break;
			case LOAD :
				ghandler.setButtonSelected("load");
				break;
			case ADD_EMPTY :
				ghandler.setButtonSelected("add_empty");
				break;
			case ADD_ABMIENT :
				ghandler.setButtonSelected("add_ambient");
				break;
			case ADD_TRIGGERAREA :
				ghandler.setButtonSelected("add_triggerarea");
				break;
		}
		if (grender.isClicked()) {
			if (grender.isClicked("debug")) {
				simplerender = true;
			}
			else if (grender.isClicked("game")) {
				simplerender = false;
			}
		}
		if (this.simplerender) {
			grender.setButtonSelected("debug");
		}
		else {
			grender.setButtonSelected("game");
		}
	}
	private GPolygon getPoly() {
		Point v[] = gpoly.getVerts();
		GPolygon po = new GPolygon(gpoly.node.pos, v, 0, getColor());
		po.node.zpos = (byte) Math.max(Byte.MIN_VALUE, Math.min(ggraph.getSliderValue("zpos"), Byte.MAX_VALUE));
		po.setGlow(ggraph.isChecked("glow"));
		if (ggraph.isChecked("glow")) {
			po.glowColor = getColor();
		}
		else {
			po.glowColor = new Color(0, 0, 0, 1);
		}
		po.setShadow(ggraph.isChecked("shadow"));
		if (ggraph.isChecked("texture")) {
			Texture t = TextureContainer.getTexture(ggraph.getText("texname"));
			if (t != null) {
				po.setTexture(t);
			}
			else {
				statM("no such texture!: " + ggraph.getText("texname"));
			}
		}
		return po;
	}
	private void handleFinishAction() {
		if (state == EditorState.ADD_POLY) {
			if (editormode == EditorMode.PHYSICS) {
				Point v[] = gpoly.getVerts();
				if (v.length >= 3) {
					float friction = gphys.getSliderValue("friction");
					float restitution = gphys.getSliderValue("restitution");
					Point p = Polygon.calcCOM(v);
					Polygon poly = new Polygon(p.add(gpoly.node.pos), v);
					float mass = Initializer.calcMass(poly, gphys.getSliderValue("mass")) * MASSSCALEFACTOR;
					Body b = new Body(poly, Floatmath.min(mass, 100));
					b.friction = friction;
					b.restitution = restitution;
					if (gphys.isChecked("static"))
						b.setStatic();
					gobj.addBody(b);
					if (gphys.isChecked("auto_add")) {
						GPolygon po = getPoly();
						gobj.addGraphicsObject(po, new GSync(b, po.node.pos.sub(b.pos), 0));
						this.gpoly.clearPoints();
					}
					this.gpoly.clearPoints();
					statM("added physics polygon");
				}
			}
			else {
				Point v[] = gpoly.getVerts();
				if (v.length >= 3) {
					gobj.addGraphicsObject(getPoly(), new GSync());
					this.gpoly.clearPoints();
					statM("added graphics polygon");
				}
			}
		}
	}
	/**
	 * set status bar message
	 * 
	 * @param message
	 */
	private void statM(String message) {
		((GuiLabel) gstatusbar.getObject("status")).setText(message);
	}
	@Override
	public void render() {
		super.render();
		if (this.simplerender) {
			renderBgGrid();
		}
		this.startCamTransformation();
		if (drawcircle) {
			GLTools.drawCircleLine(bpoint, bpoint.distance(keyListener.mp), 0, Color.white, false);
		}
		if (drawrect) {
			if (state != EditorState.LOAD) {
				if (hasTexConstraint) {
					Point d = bpoint.sub(keyListener.mp);
					float l = d.length();
					float asp = (float) tex.width / (float) tex.height;
					GLTools.drawRectWire(bpoint, l, l / asp, 0, Color.white);
				}
				else {
					Point d = bpoint.sub(keyListener.mp);
					GLTools.drawRectWire(bpoint.add(keyListener.mp).mul(0.5f), Math.abs(d.x), Math.abs(d.y), 0, Color.white);
				}
			}
			else {
				float xmin = Math.min(bpoint.x, keyListener.mp.x);
				float xmax = Math.max(bpoint.x, keyListener.mp.x);
				float ymin = Math.min(bpoint.y, keyListener.mp.y);
				float ymax = Math.max(bpoint.y, keyListener.mp.y);
				float s = Floatmath.max(xmax - xmin, ymax - ymin);
				GLTools.drawRectWire(bpoint.add(new Point(s / 2, s / 2)), s, s, 0, Color.white);
			}
		}
		if (bodyselected) {
			this.gphysettings.setVisible(true);
			gphysettings.moveTo(new Point(width - 170, height - 10));
			for (Body b : selbodies) {
				GLTools.drawRectWire(b.pos, b.width * 2, b.height * 2, 0, Color.yellow);
			}
		}
		else {
			this.gphysettings.setVisible(false);
		}
		if (groselected) {
			this.ggraphsettings.setVisible(true);
			ggraphsettings.moveTo(new Point(width - 170 + (bodyselected ? -180 : 0), height - 10));
			for (GraphicsObject g : selgros) {
				GLTools.drawRectWire(g.node.pos, g.node.boundingrad * 2, g.node.boundingrad * 2, 0, Color.yellow);
			}
		}
		else {
			this.ggraphsettings.setVisible(false);
		}
		if (state == EditorState.CONNECT) {
			if (bodyselected && selbody != null)
				GLTools.drawRectWire(selbody.pos, selbody.width * 2, selbody.height * 2, 0, Color.yellow);
			if (bodyselected) {
				GraphicsObject g = gobj.getGROAt(keyListener.mp);
				if (g != null) {
					GLTools.drawRectWire(g.node.pos, g.node.boundingrad * 2, g.node.boundingrad * 2, 0, Color.red);
				}
			}
		}
		if (selectline) {
			GLTools.drawLine(bpoint, keyListener.mp, Color.red);
		}
		if (anchorset) {
			GLTools.drawLine(bpoint, keyListener.mp, Color.yellow);
		}
		if (this.showNames && this.simplerender) {
			for (int i = 0; i < gobj.numBodies; i++) {
				String n = gobj.getName(gobj.getBody(i));
				n = n != null ? n : "";
				GLTools.drawText(gobj.getBody(i).pos, n, Color.green, 1 / zoom);
			}
			for (int i = 0; i < gobj.numGraphicsObjects; i++) {
				String n = gobj.getName(gobj.getGraphicsObject(i));
				n = n != null ? n : "";
				GLTools.drawText(gobj.getGraphicsObject(i).node.pos, n, Color.blue, 1 / zoom);
			}
		}
		this.stopCamTransformation();
		grender.drawAll();
		ghandler.drawAll();
		gstatusbar.drawAll();
		ggraphsettings.drawAll();
		gphysettings.drawAll();
		gphys.moveTo(new Point(1, height - (2 + ghandler.getHeight())));
		ggraph.moveTo(new Point(1, height - (2 + ghandler.getHeight())));
		if (this.editormode == EditorMode.PHYSICS) {
			gphys.drawAll();
			if (gphys.isChecked("auto_add")) {
				ggraph.moveTo(new Point(1, height - (2 + ghandler.getHeight() + gphys.getHeight())));
				ggraph.drawAll();
			}
		}
		else {
			ggraph.drawAll();
		}
		if (showConsole) {
			Console.draw();
		}
		if (showprofiler)
			Profiler.drawProfiler();
	}
	private void renderBgGrid() {
		int gridsize = 20;
		int xoff = (((int) campos.x) / gridsize) * gridsize;
		int yoff = (((int) campos.y) / gridsize) * gridsize;
		int xs = 100;
		GL11.glPushMatrix();
		GL11.glScalef(zoom, zoom, 1);
		GL11.glTranslatef(-campos.x + ((width / 2.0f) * (1.0f / zoom)), -campos.y + ((height / 2.0f) * (1.0f / zoom)), 0);
		for (int i = -xs; i < xs; i++) {
			GLTools.drawLine(new Point(i * gridsize + xoff, -2000 + yoff), new Point(i * gridsize + xoff, 2000 + yoff), new Color(0, 0, 0, 0.1f));
			GLTools.drawLine(new Point(-2000 + xoff, i * gridsize + yoff), new Point(2000 + xoff, i * gridsize + yoff), new Color(0, 0, 0, 0.1f));
		}
		GL11.glPopMatrix();
		/*
		 * for(int i=-100;i<100;i++){ GLTools.drawLine(new Point(campos.x + i*10,-this.width*(1/zoom)), new Point(campos.x + i*10,-this.width*(1/zoom)),new Color(0,0,0,1)); }
		 */
	}
	protected void cancleAll() {
		cancleAllEditMode();
		hasTexConstraint = false;
		this.state = EditorState.NONE;
		this.drawcircle = false;
		anchorset = false;
		this.bodyselected = false;
		groselected = false;
		selgros.clear();
		selbodies.clear();
		gpoly.clearPoints();
		statM("");
	}
	@Override
	protected void control() {
		keyListener.clear();
		keyListener.mp = this.getMousePosTransformed();
		while (Keyboard.next()) {
			keyListener.addKey(Keyboard.getEventKey(), Keyboard.getEventKeyState());
			if (Keyboard.getEventKeyState())
				this.writeChar(Keyboard.getEventCharacter());
			if (Keyboard.getEventKey() == Keyboard.KEY_F9 && !Keyboard.getEventKeyState()) {
				showConsole = !showConsole;
			}
			else if (Keyboard.getEventKey() == Keyboard.KEY_F12 && !Keyboard.getEventKeyState()) {
				simplerender = !simplerender;
			}
			else
			/*
			 * if(Keyboard.getEventKey() == Keyboard.KEY_F7 && !Keyboard.getEventKeyState()) { showprofiler = !showprofiler; }
			 */
			if (Keyboard.getEventKey() == Keyboard.KEY_F8 && !Keyboard.getEventKeyState()) {
				takeScreenshot();
			}
			else if (Keyboard.getEventKey() == Keyboard.KEY_ESCAPE && !Keyboard.getEventKeyState()) {
				cancleAll();
			}
			else if (Keyboard.getEventKey() == Keyboard.KEY_LEFT && inEditMode() && !Keyboard.getEventKeyState()) {
				this.moveCurser(-1);
			}
			else if (Keyboard.getEventKey() == Keyboard.KEY_R && !inEditMode() && !Keyboard.getEventKeyState()) {
				state = EditorState.ROTATE;
			}
			else if (Keyboard.getEventKey() == Keyboard.KEY_F7 && !Keyboard.getEventKeyState()) {
				showprofiler = !showprofiler;
			}
			if (Keyboard.getEventKey() == Keyboard.KEY_M && !Keyboard.getEventKeyState() && !inEditMode()) {
				state = EditorState.MOVE;
			}
			else if (Keyboard.getEventKey() == Keyboard.KEY_S && !Keyboard.getEventKeyState() && !inEditMode()) {
				state = EditorState.SCALE;
			}
			else if (Keyboard.getEventKey() == Keyboard.KEY_RIGHT && inEditMode() && !Keyboard.getEventKeyState()) {
				this.moveCurser(1);
			}
			else if (Keyboard.getEventKey() == Keyboard.KEY_BACK && inEditMode() && !Keyboard.getEventKeyState()) {
				this.deleteChar();
			}
			else if (Keyboard.getEventKey() == Keyboard.KEY_DELETE && !inEditMode() && !Keyboard.getEventKeyState()) {
				if (groselected) {
					for (GraphicsObject g : selgros)
						gobj.remGraphicsObject(g);
					selgro = null;
					groselected = false;
					selgros.clear();
				}
				if (bodyselected) {
					if (gphys.isChecked("auto_add")) {
						for (Body b : selbodies)
							gobj.remBodyWithGraphics(b);
					}
					else
						for (Body b : selbodies)
							gobj.remBody(b);
					selbody = null;
					bodyselected = false;
					selbodies.clear();
				}
			}
			else if (!inEditMode() && Keyboard.getEventKey() == Keyboard.KEY_SPACE && !Keyboard.getEventKeyState()) {
				gobj.saveLoadPhysicState();
				game.engine.startStopPhysics();
				if (game.engine.isDophysics()) {
					statM("started physics engine");
				}
				else {
					statM("stoped physics engine");
				}
			}
			else if (Keyboard.getEventKey() == Keyboard.KEY_RETURN && !Keyboard.getEventKeyState()) {
				handleFinishAction();
				this.cancleAllEditMode();
			}
		}
		while (Mouse.next()) {
			keyListener.addButton(Mouse.getEventButton(), Mouse.getEventButtonState());
		}
		float movespeed = 5 * 1.0f / zoom;
		if (!inEditMode() && Keyboard.isKeyDown(Keyboard.KEY_UP)) {
			this.campos.y += movespeed;
		}
		if (!inEditMode() && Keyboard.isKeyDown(Keyboard.KEY_DOWN)) {
			this.campos.y -= movespeed;
		}
		if (!inEditMode() && Keyboard.isKeyDown(Keyboard.KEY_RIGHT)) {
			this.campos.x += movespeed;
		}
		if (!inEditMode() && Keyboard.isKeyDown(Keyboard.KEY_LEFT)) {
			this.campos.x -= movespeed;
		}
		if (keyListener.isButtonTouched(2)) {
			cmove = keyListener.mp;
		}
		if (keyListener.isButtonPressed(2)) {
			Point delta = keyListener.mp.sub(cmove).mul(-1);
			campos.sAdd(delta);
			cmove = keyListener.mp.add(delta);
		}
		if (!inEditMode() && keyListener.isKeyTouched(Keyboard.KEY_N)) {
			showNames = !showNames;
		}
		if (!inEditMode() && keyListener.isKeyTouched(Keyboard.KEY_B)) {
			this.state = EditorState.RSELECT;
			drawrect = false;
			drawcircle = false;
			gpoly.clearPoints();
			statM("click and drag to select a rect of objects");
		}
		if (keyListener.isKeyReleased(Keyboard.KEY_F5)) {
			Log.g("reloading shader!");
			Compositor.reloadShader();
		}
		int wh = Mouse.getDWheel();
		if (wh < 0) {
			this.setZoom(zoom * 0.9f);
		}
		else if (wh > 0) {
			this.setZoom(zoom * 1.1f);
		}
		if (!inEditMode() && keyListener.isKeyPressed(Keyboard.KEY_LCONTROL) && keyListener.isKeyTouched(Keyboard.KEY_C)) {
			gobj.copy(selbodies, selgros);
		}
		if (!inEditMode() && keyListener.isKeyPressed(Keyboard.KEY_LCONTROL) && keyListener.isKeyTouched(Keyboard.KEY_V)) {
			gobj.paste(keyListener.mp);
		}
		if (!inEditMode() && keyListener.isKeyReleased(Keyboard.KEY_F4)) {
			ProgramLauncher.startServer("level0");
		}
		ghandler.moveTo(new Point(1, height - 1));
		gstatusbar.moveCenterTo(new Point(width / 2, 20));
		grender.moveTo(new Point(210, height - 1));
		if (keyListener.isButtonPressed(0)) {
			setAllClick();
		}
		if (keyListener.isButtonTouched(0)) {
			clickAll();
		}
		else {
			if (!keyListener.isButtonPressed(0)) {
				this.unclickAll();
			}
		}
	}
	private void cancleAllEditMode() {
		ghandler.cancleEditMode();
		ggraphsettings.cancleEditMode();
		gphysettings.cancleEditMode();
		ggraph.cancleEditMode();
		gphys.cancleEditMode();
	}
	private void setAllClick() {
		Point mp = getMousePosOnScreen();
		ghandler.setClick(mp);
		ggraphsettings.setClick(mp);
		gphysettings.setClick(mp);
		grender.setClick(mp);
		if (editormode == EditorMode.PHYSICS) {
			gphys.setClick(mp);
			if (gphys.isChecked("auto_add")) {
				ggraph.setClick(mp);
			}
		}
		else {
			ggraph.setClick(mp);
		}
	}
	private void moveCurser(int i) {
		ghandler.moveCursor(i);
		ggraphsettings.moveCursor(i);
		gphysettings.moveCursor(i);
		ggraph.moveCursor(i);
		gphys.moveCursor(i);
	}
	private void deleteChar() {
		ghandler.deleteChar();
		ggraphsettings.deleteChar();
		gphysettings.deleteChar();
		ggraph.deleteChar();
		gphys.deleteChar();
	}
	private void writeChar(char key) {
		ghandler.applyKeyPress(key);
		ggraph.applyKeyPress(key);
		gphys.applyKeyPress(key);
		ggraphsettings.applyKeyPress(key);
		gphysettings.applyKeyPress(key);
	}
	private void clickAll() {
		Point mp = getMousePosOnScreen();
		ghandler.handleClick(mp);
		ggraphsettings.handleClick(mp);
		gphysettings.handleClick(mp);
		grender.handleClick(mp);
		if (editormode == EditorMode.PHYSICS) {
			gphys.handleClick(mp);
			if (gphys.isChecked("auto_add")) {
				ggraph.handleClick(mp);
			}
		}
		else {
			ggraph.handleClick(mp);
		}
	}
	private void unclickAll() {
		ghandler.unClickAll();
		grender.unClickAll();
		ggraphsettings.unClickAll();
		gphysettings.unClickAll();
		ggraph.unClickAll();
		gphys.unClickAll();
	}
	private boolean inEditMode() {
		return ghandler.inTextEditMode() || ggraphsettings.inTextEditMode() || gphysettings.inTextEditMode() || gphys.inTextEditMode() || ggraph.inTextEditMode();
	}
}
